import tkinter as tk
from tkinter import messagebox, ttk
import redis
import ast
import utils

class PurchaseManagement:
    def __init__(self, parent):
        self.parent = parent
        self.create_widgets()
        self.load_pay_main()

    def create_widgets(self):
        self.frame = tk.Frame(self.parent)
        self.frame.pack(fill=tk.BOTH, expand=True)

        # Main Treeview with Scrollbars
        self.tree_main_frame = tk.Frame(self.frame)
        self.tree_main_frame.pack(fill=tk.BOTH, expand=True)

        self.tree_main_scrollbar_y = tk.Scrollbar(self.tree_main_frame, orient=tk.VERTICAL)
        self.tree_main_scrollbar_y.pack(side=tk.RIGHT, fill=tk.Y)

        self.tree_main_scrollbar_x = tk.Scrollbar(self.tree_main_frame, orient=tk.HORIZONTAL)
        self.tree_main_scrollbar_x.pack(side=tk.BOTTOM, fill=tk.X)

        self.tree_main = ttk.Treeview(self.tree_main_frame, columns=("Pid", "Eid", "Pcount", "Ptotal", "Pdate", "other"), 
                                      show='headings', yscrollcommand=self.tree_main_scrollbar_y.set, xscrollcommand=self.tree_main_scrollbar_x.set)
        self.tree_main.heading("Pid", text="Purchase ID")
        self.tree_main.heading("Eid", text="Employee ID")
        self.tree_main.heading("Pcount", text="Quantity")
        self.tree_main.heading("Ptotal", text="Total Price")
        self.tree_main.heading("Pdate", text="Purchase Date")
        self.tree_main.heading("other", text="Remarks")
        self.tree_main.pack(fill=tk.BOTH, expand=True)
        self.tree_main_scrollbar_y.config(command=self.tree_main.yview)
        self.tree_main_scrollbar_x.config(command=self.tree_main.xview)

        self.tree_main.bind("<<TreeviewSelect>>", self.on_tree_main_select)

        # Detail Treeview with Scrollbars
        self.tree_detail_frame = tk.Frame(self.frame)
        self.tree_detail_frame.pack(fill=tk.BOTH, expand=True)

        self.tree_detail_scrollbar_y = tk.Scrollbar(self.tree_detail_frame, orient=tk.VERTICAL)
        self.tree_detail_scrollbar_y.pack(side=tk.RIGHT, fill=tk.Y)

        self.tree_detail_scrollbar_x = tk.Scrollbar(self.tree_detail_frame, orient=tk.HORIZONTAL)
        self.tree_detail_scrollbar_x.pack(side=tk.BOTTOM, fill=tk.X)

        self.tree_detail = ttk.Treeview(self.tree_detail_frame, columns=("PDid", "Pid", "Gid", "Pcount", "GPay", "total", "other"), 
                                        show='headings', yscrollcommand=self.tree_detail_scrollbar_y.set, xscrollcommand=self.tree_detail_scrollbar_x.set)
        self.tree_detail.heading("PDid", text="Detail ID")
        self.tree_detail.heading("Pid", text="Purchase ID")
        self.tree_detail.heading("Gid", text="Product ID")
        self.tree_detail.heading("Pcount", text="Quantity")
        self.tree_detail.heading("GPay", text="Unit Price")
        self.tree_detail.heading("total", text="Total Price")
        self.tree_detail.heading("other", text="Remarks")
        self.tree_detail.pack(fill=tk.BOTH, expand=True)
        self.tree_detail_scrollbar_y.config(command=self.tree_detail.yview)
        self.tree_detail_scrollbar_x.config(command=self.tree_detail.xview)

        self.tree_detail.bind("<<TreeviewSelect>>", self.on_tree_detail_select)

        self.button_frame = tk.Frame(self.parent)
        self.button_frame.pack(fill=tk.X)

        self.add_main_button = tk.Button(self.button_frame, text="Add Purchase", command=self.add_pay_main)
        self.add_main_button.pack(side=tk.LEFT, padx=5, pady=5)

        self.update_main_button = tk.Button(self.button_frame, text="Update Purchase", command=self.update_pay_main)
        self.update_main_button.pack(side=tk.LEFT, padx=5, pady=5)

        self.delete_main_button = tk.Button(self.button_frame, text="Delete Purchase", command=self.delete_pay_main)
        self.delete_main_button.pack(side=tk.LEFT, padx=5, pady=5)

        self.export_main_button = tk.Button(self.button_frame, text="Export to .xsv", command=self.export_pay_main)
        self.export_main_button.pack(side=tk.LEFT, padx=5, pady=5)

        self.add_detail_button = tk.Button(self.button_frame, text="Add Detail", command=self.add_pay_detail)
        self.add_detail_button.pack(side=tk.LEFT, padx=5, pady=5)

        self.update_detail_button = tk.Button(self.button_frame, text="Update Detail", command=self.update_pay_detail)
        self.update_detail_button.pack(side=tk.LEFT, padx=5, pady=5)

        self.delete_detail_button = tk.Button(self.button_frame, text="Delete Detail", command=self.delete_pay_detail)
        self.delete_detail_button.pack(side=tk.LEFT, padx=5, pady=5)

    def load_pay_main(self):
        self.tree_main.delete(*self.tree_main.get_children())
        r = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True)
        pay_mains = r.hgetall('tb_pay_main')
        for pid, pay_main in pay_mains.items():
            pay_main_data = ast.literal_eval(pay_main)
            print(f"Loading pay_main_data: {pay_main_data}")  # Debugging statement
            self.tree_main.insert("", "end", values=(
                pid, 
                pay_main_data.get('Eid', 'N/A'), 
                pay_main_data.get('Pcount', '0'), 
                pay_main_data.get('Ptotal', '0.0'), 
                pay_main_data.get('Pdate', 'N/A'), 
                pay_main_data.get('other', '')
            ))

    def on_tree_main_select(self, event):
        selected_items = self.tree_main.selection()
        if selected_items:
            selected_item = selected_items[0]
            self.selected_pay_main = self.tree_main.item(selected_item, "values")
            self.load_pay_detail(self.selected_pay_main[0])
        else:
            self.selected_pay_main = None

    def load_pay_detail(self, pid):
        self.tree_detail.delete(*self.tree_detail.get_children())
        r = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True)
        pay_details = r.hgetall('tb_pay_detail')
        for pdid, pay_detail in pay_details.items():
            pay_detail_data = ast.literal_eval(pay_detail)
            if 'Pid' in pay_detail_data and pay_detail_data['Pid'] == pid:
                self.tree_detail.insert("", "end", values=(
                    pdid, 
                    pay_detail_data.get('Pid', 'N/A'), 
                    pay_detail_data.get('Gid', 'N/A'), 
                    pay_detail_data.get('Pcount', '0'), 
                    pay_detail_data.get('GPay', '0.0'), 
                    pay_detail_data.get('total', '0.0'), 
                    pay_detail_data.get('other', '')
                ))

    def on_tree_detail_select(self, event):
        selected_items = self.tree_detail.selection()
        if selected_items:
            selected_item = selected_items[0]
            self.selected_pay_detail = self.tree_detail.item(selected_item, "values")
        else:
            self.selected_pay_detail = None

    def add_pay_main(self):
        self.pay_main_popup("Add Purchase", self.save_new_pay_main)

    def update_pay_main(self):
        if hasattr(self, 'selected_pay_main') and self.selected_pay_main:
            self.pay_main_popup("Update Purchase", self.save_updated_pay_main, self.selected_pay_main)
        else:
            messagebox.showwarning("Warning", "Please select a purchase first")

    def delete_pay_main(self):
        if hasattr(self, 'selected_pay_main') and self.selected_pay_main:
            r = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True)
            r.hdel('tb_pay_main', self.selected_pay_main[0])
            self.load_pay_main()
        else:
            messagebox.showwarning("Warning", "Please select a purchase first")

    def export_pay_main(self):
        r = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True)
        pay_main_data = r.hgetall('tb_pay_main')
        pay_detail_data = r.hgetall('tb_pay_detail')
        combined_data = {**pay_main_data, **pay_detail_data}
        utils.export_to_csv(combined_data, 'pay_main_and_details.csv')

    def generate_id(self, prefix):
        r = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True)
        if prefix == 'Pid':
            return str(r.incr('Pid_counter'))
        elif prefix == 'PDid':
            return str(r.incr('PDid_counter'))

    def pay_main_popup(self, title, save_command, pay_main_data=None):
        print(f"Opening popup: {title}")
        popup = tk.Toplevel(self.parent)
        popup.title(title)
        popup.geometry("600x600")  # Increased window size

        fields = ["Pid", "Eid", "Pcount", "Ptotal", "Pdate", "other"]
        entries = {}

        for field in fields:
            print(f"Creating label and entry for field: {field}")
            label = tk.Label(popup, text=field.replace('_', ' ').title())
            label.pack(pady=5)
            entry = tk.Entry(popup)
            entry.pack(pady=5)
            entries[field] = entry

        if pay_main_data:
            print(f"Populating popup with existing data: {pay_main_data}")
            for i, field in enumerate(fields):
                entries[field].insert(0, pay_main_data[i])
                if field in ["Pid", "Pcount", "Ptotal"]:
                    entries[field].config(state='readonly')  # Make the ID, quantity, and total_price fields read-only
        else:
            print("Creating new entry fields")
            # Generate new ID for new entry
            new_pid = self.generate_id('Pid')
            print(f"Generated new Purchase ID: {new_pid}")
            entries["Pid"].insert(0, new_pid)
            entries["Pid"].config(state='readonly')  # Make the ID field read-only
            entries["Pcount"].insert(0, "0")
            entries["Pcount"].config(state='readonly')  # Make the quantity field read-only
            entries["Ptotal"].insert(0, "0")
            entries["Ptotal"].config(state='readonly')  # Make the total_price field read-only

        save_button = tk.Button(popup, text="Save", command=lambda: save_command(entries, popup))
        save_button.pack(pady=20)
        print("Popup creation complete")

    def pay_detail_popup(self, title, save_command, pid, pay_detail_data=None):
        print(f"Opening detail popup: {title}")
        popup = tk.Toplevel(self.parent)
        popup.title(title)
        popup.geometry("600x600")  # Increased window size

        fields = ["PDid", "Pid", "Gid", "Pcount", "GPay", "total", "other"]
        entries = {}

        def update_total(*args):
            try:
                quantity = float(entries["Pcount"].get())
                unit_price = float(entries["GPay"].get())
                total = quantity * unit_price
                entries["total"].config(state=tk.NORMAL)
                entries["total"].delete(0, tk.END)
                entries["total"].insert(0, str(total))
                entries["total"].config(state='readonly')
            except ValueError:
                entries["total"].config(state=tk.NORMAL)
                entries["total"].delete(0, tk.END)
                entries["total"].insert(0, "0.0")
                entries["total"].config(state='readonly')

        for field in fields:
            print(f"Creating label and entry for field: {field}")
            label = tk.Label(popup, text=field.replace('_', ' ').title())
            label.pack(pady=5)
            entry = tk.Entry(popup)
            entry.pack(pady=5)
            entries[field] = entry

        if pay_detail_data:
            print(f"Populating detail popup with existing data: {pay_detail_data}")
            for i, field in enumerate(fields):
                entries[field].insert(0, pay_detail_data[i])
                if field in ["PDid", "Pid", "total"]:
                    entries[field].config(state='readonly')  # Make the ID and total fields read-only
        else:
            print("Creating new detail entry fields")
            # Generate new ID for new entry
            new_pdid = self.generate_id('PDid')
            print(f"Generated new Detail ID: {new_pdid}")
            entries["PDid"].insert(0, new_pdid)
            entries["PDid"].config(state='readonly')  # Make the ID field read-only
            entries["Pid"].insert(0, pid)
            entries["Pid"].config(state='readonly')  # Make the ID field read-only
            entries["total"].insert(0, "0.0")
            entries["total"].config(state='readonly')  # Make the total field read-only

        entries["Pcount"].bind("<KeyRelease>", update_total)
        entries["GPay"].bind("<KeyRelease>", update_total)

        save_button = tk.Button(popup, text="Save", command=lambda: save_command(entries, popup))
        save_button.pack(pady=20)
        print("Detail popup creation complete")

    def save_new_pay_main(self, entries, popup):
        try:
            pay_main_data = {field: entry.get() for field, entry in entries.items()}
            print(f"Saving new pay_main data: {pay_main_data}")  # Debug statement
            r = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True)
            r.hset('tb_pay_main', pay_main_data['Pid'], str(pay_main_data))
            self.load_pay_main()
            popup.destroy()
        except Exception as e:
            print(f"Error saving new pay main: {e}")
            messagebox.showerror("Error", f"Unable to save purchase: {e}")

    def save_updated_pay_main(self, entries, popup):
        try:
            pay_main_data = {field: entry.get() for field, entry in entries.items()}
            print(f"Saving updated pay_main data: {pay_main_data}")  # Debug statement
            r = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True)
            r.hset('tb_pay_main', pay_main_data['Pid'], str(pay_main_data))
            self.load_pay_main()
            popup.destroy()
        except Exception as e:
            print(f"Error saving updated pay main: {e}")
            messagebox.showerror("Error", f"Unable to update purchase: {e}")

    def add_pay_detail(self):
        if hasattr(self, 'selected_pay_main') and self.selected_pay_main:
            self.pay_detail_popup("Add Detail", self.save_new_pay_detail, self.selected_pay_main[0])
        else:
            messagebox.showwarning("Warning", "Please select a purchase first")

    def update_pay_detail(self):
        if hasattr(self, 'selected_pay_detail') and self.selected_pay_detail:
            self.pay_detail_popup("Update Detail", self.save_updated_pay_detail, self.selected_pay_main[0], self.selected_pay_detail)
        else:
            messagebox.showwarning("Warning", "Please select a detail first")

    def delete_pay_detail(self):
        if hasattr(self, 'selected_pay_detail') and self.selected_pay_detail:
            try:
                r = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True)
                r.hdel('tb_pay_detail', self.selected_pay_detail[0])
                self.update_pay_main_totals(self.selected_pay_main[0])
                self.load_pay_detail(self.selected_pay_main[0])
            except Exception as e:
                print(f"Error deleting pay detail: {e}")
                messagebox.showerror("Error", f"Unable to delete detail: {e}")
        else:
            messagebox.showwarning("Warning", "Please select a detail first")

    def save_new_pay_detail(self, entries, popup):
        try:
            pay_detail_data = {field: entry.get() for field, entry in entries.items()}
            pay_detail_data['total'] = str(float(pay_detail_data['Pcount']) * float(pay_detail_data['GPay']))
            print(f"Saving new pay_detail data: {pay_detail_data}")  # Debug statement
            r = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True)
            r.hset('tb_pay_detail', pay_detail_data['PDid'], str(pay_detail_data))
            self.update_pay_main_totals(pay_detail_data['Pid'])
            self.load_pay_detail(pay_detail_data['Pid'])
            popup.destroy()
        except Exception as e:
            print(f"Error saving new pay detail: {e}")
            messagebox.showerror("Error", f"Unable to save detail: {e}")

    def save_updated_pay_detail(self, entries, popup):
        try:
            pay_detail_data = {field: entry.get() for field, entry in entries.items()}
            pay_detail_data['total'] = str(float(pay_detail_data['Pcount']) * float(pay_detail_data['GPay']))
            print(f"Saving updated pay_detail data: {pay_detail_data}")  # Debug statement
            r = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True)
            r.hset('tb_pay_detail', pay_detail_data['PDid'], str(pay_detail_data))
            self.update_pay_main_totals(pay_detail_data['Pid'])
            self.load_pay_detail(pay_detail_data['Pid'])
            popup.destroy()
        except Exception as e:
            print(f"Error saving updated pay detail: {e}")
            messagebox.showerror("Error", f"Unable to update detail: {e}")

    def update_pay_main_totals(self, pid):
        try:
            r = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True)
            pay_details = r.hgetall('tb_pay_detail')
            total = sum(float(ast.literal_eval(detail).get('total', 0)) for detail in pay_details.values() if 'Pid' in ast.literal_eval(detail) and ast.literal_eval(detail)['Pid'] == pid)
            quantity = sum(int(ast.literal_eval(detail).get('Pcount', 0)) for detail in pay_details.values() if 'Pid' in ast.literal_eval(detail) and ast.literal_eval(detail)['Pid'] == pid)
            pay_main = ast.literal_eval(r.hget('tb_pay_main', pid))
            pay_main['Ptotal'] = str(total)
            pay_main['Pcount'] = str(quantity)
            print(f"Updating pay main totals: {pay_main}")  # Debug statement
            r.hset('tb_pay_main', pid, str(pay_main))
            self.load_pay_main()
        except Exception as e:
            print(f"Error updating pay main totals: {e}")
            messagebox.showerror("Error", f"Unable to update purchase totals: {e}")

if __name__ == "__main__":
    root = tk.Tk()
    app = PurchaseManagement(root)
    root.mainloop()
